param(
		[boolean]$StreamMode = $false,
		[string]$Prompt = "test"
	 )

function Out-Request {
	param(
		$Request
	 )
	Write-Host "<<< Request <<< " 
	Write-Host "Method: " -NoNewline
	Write-Host $Request.Method
	Write-Host "RequestUri: " -NoNewline
	Write-Host $Request.RequestUri
	Write-Host "Version: " -NoNewline
	Write-Host $Request.Version
	Write-Host "Headers: " -NoNewline
	$headers = $Request.Headers | ConvertTo-Json -Depth 5
	Write-Host $headers
	Write-Host "Body: " -NoNewline
	$requestBody = $Request.Content | ConvertTo-Json -Depth 5
	Write-Host $requestBody
	Write-Host "--- End of Request --- " 
}

# 参数
# model：（必需）模型名称
# prompt：生成响应的提示
# suffix：模型响应后的文本
# images：（可选）base64 编码图像列表（对于多模态模型，例如llava)
# 高级参数（可选）：
# format：返回响应的格式。格式可以是json或 JSON 架构
# options：Modelfile 文档中列出的其他模型参数，例如temperature
# system：系统消息更改为（覆盖Modelfile)
# template：要使用的提示模板（覆盖Modelfile)
# stream：如果false响应将作为单个响应对象返回，而不是对象流
# raw：如果true不会对提示应用任何格式。您可以选择使用raw参数（如果要在对 API 的请求中指定完整模板化提示）
# keep_alive：控制模型在请求后加载到内存中的时间（默认值：5m)
# context（已弃用）：从上一个请求返回的 context 参数/generate，这可用于保持简短的对话记忆
function Invoke-GenerateStream {
 	param(
		[string]$Uri = "http://localhost:11434/api/generate",
		[string]$Model = "deepseek-r1:latest",
		[boolean]$StreamMode = $true,
		[string]$Prompt = "test"
		)

	Add-Type -AssemblyName System.Net.Http
	$client = [System.Net.Http.HttpClient]::new()
	# $client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json")
	$request = [System.Net.Http.HttpRequestMessage]::new(
			[System.Net.Http.HttpMethod]::Post,
			$Uri
			)
	$body = @{
		model = $Model
		prompt = $Prompt
		stream = $StreamMode
	} | ConvertTo-Json
	$request.Content = [System.Net.Http.StringContent]::new(
			$body,
			[System.Text.Encoding]::UTF8,
			"application/json"
			)
	Out-Request $request
	# 流式接收
	$response = $client.SendAsync(
			$request,
			[System.Net.Http.HttpCompletionOption]::ResponseHeadersRead
			).Result
	try {
		if($StreamMode) {
			# 实时输出
			$stream = $response.Content.ReadAsStreamAsync().Result
			$reader = [System.IO.StreamReader]::new($stream)
			Write-Host ">>> Response >>> " 
			$done = $false
			Write-Host "Output: " -NoNewline
			while (-not $reader.EndOfStream -and -not $done) {
				$line = $reader.ReadLine()
				if ($line) {
					# Write-Host $line
					$json = $line | ConvertFrom-Json
					# Write-Host -NoNewline $json
					$done = $json.done
					Write-Host -NoNewline $json.response
					if($done) {
						Write-Host "`n--- End of Response --- `nStatistics: " -NoNewline 
						$statistics = @{
							done_reason = $json.done_reason 
							total_duration = $json.total_duration 
							load_duration = $json.load_duration 
							prompt_eval_count = $json.prompt_eval_count
							prompt_eval_duration = $json.prompt_eval_duration
							eval_count = $json.eval_count
							eval_duration = $json.eval_duration
						} | ConvertTo-Json -Depth 5
						Write-Host $statistics
					}
				}
			}
		} else {
			Write-Host ">>> Response >>> " 
			Write-Host $response
			Write-Host "StatusCode: " -NoNewline 
			Write-Host $response.StatusCode
			Write-Host "ReasonPhrase: " -NoNewline 
			Write-Host $response.ReasonPhrase
			Write-Host "Version: " -NoNewline 
			Write-Host $response.Version
			Write-Host "Headers: " -NoNewline 
			Write-Host $response.Headers
			Write-Host "Content: " -NoNewline 
			$content = $response.Content | ConvertTo-Json -Depth 5
			Write-Host $content
			Write-Host "--- End of Response ---"
		}
	} finally {
		if($StreamMode) {
			$reader.Dispose()
			$client.Dispose()
		}
	}
}

$response = Invoke-GenerateStream -Prompt $Prompt -StreamMode $StreamMode

